package co.salehi.web;

import java.awt.Color;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;

import org.springframework.roo.addon.web.mvc.controller.RooWebScaffold;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import co.salehi.domain.Battery;
import co.salehi.domain.Cart;
import co.salehi.domain.LabourCharge;
import co.salehi.domain.Operator;
import co.salehi.domain.Ring;
import co.salehi.domain.Sell;
import co.salehi.domain.Tyre;
import co.salehi.util.Util;

import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.FontFactory;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;

@RooWebScaffold(path = "sells", formBackingObject = Sell.class)
@RequestMapping("/sells")
@Controller
public class SellController {

	public static BaseColor HEADER_COLOR = new BaseColor(new Color(210, 210,
			210));
	public static BaseColor TOTAL_COLOR = new BaseColor(
			new Color(240, 240, 240));
	public static Font PDF_SMALL_FONT_BOLD_Orig = FontFactory.getFont(
			FontFactory.TIMES_BOLD, 10);
	public static Font PDF_SMALL_FONT_BOLD = FontFactory.getFont(
			FontFactory.HELVETICA_BOLD, 10);
	public static Font PDF_SMALL_FONT_Orig = FontFactory.getFont(
			FontFactory.TIMES_ROMAN, 10);
	public static Font PDF_SMALL_FONT = FontFactory.getFont(
			FontFactory.HELVETICA, 10);
	public static Font PDF_LARGE_FONT_Orig = FontFactory.getFont(
			FontFactory.TIMES_BOLD, 14);
	public static Font PDF_LARGE_FONT = FontFactory.getFont(
			FontFactory.HELVETICA_BOLD, 14);

	@RequestMapping(value = "/{id}", method = RequestMethod.GET)
	public String show(@PathVariable("id") Long id, Model uiModel,
			HttpServletRequest request, HttpServletResponse response) {
		response.setContentType("application/pdf");
		response.setHeader("Content-disposition", "attachment; filename="
				+ "receipt.pdf");
		Document document = new Document();
		try {
			PdfWriter.getInstance(document, response.getOutputStream());
			document.open();
			printToDoc(document, Sell.findSell(id));
			document.close();
		} catch (DocumentException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

	private void printToDoc(Document document, Sell sell)
			throws DocumentException {
		
		PdfPTable customerInfoTable = new PdfPTable(2);
		
		PdfPCell customerNameCell = new PdfPCell(new Phrase("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nCustomer: " + sell.getName() + "\n\n",
				PDF_SMALL_FONT_Orig));
		customerNameCell.setBorder(0);
		customerInfoTable.addCell(customerNameCell);
		
		PdfPCell dateCell = new PdfPCell(new Phrase("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nDate: " + new SimpleDateFormat("dd MMMMM yyyy").format(sell.getSellDate()) + "\n\n",
				PDF_SMALL_FONT_Orig));
		dateCell.setBorder(0);
		customerInfoTable.addCell(dateCell);
		
		document.add(customerInfoTable);

		double receiptPrice = 0;

		PdfPTable table = new PdfPTable(2);

		PdfPCell itemHeader = new PdfPCell(new Phrase("Item",
				PDF_SMALL_FONT_BOLD_Orig));
		itemHeader.setBackgroundColor(HEADER_COLOR);
		itemHeader.setHorizontalAlignment(Element.ALIGN_CENTER);
		table.addCell(itemHeader);

		PdfPCell priceHeader = new PdfPCell(new Phrase("Price",
				PDF_SMALL_FONT_BOLD_Orig));
		priceHeader.setBackgroundColor(HEADER_COLOR);
		priceHeader.setHorizontalAlignment(Element.ALIGN_CENTER);
		table.addCell(priceHeader);

		DateFormat format = new SimpleDateFormat("dd-MM-yyyy");

		for (Tyre tyre : sell.getTyres()) {

			PdfPCell descriptionCell = new PdfPCell(new Phrase(tyre.getName(),
					PDF_SMALL_FONT_Orig));
			descriptionCell.setHorizontalAlignment(Element.ALIGN_LEFT);
			table.addCell(descriptionCell);

			double price = tyre.getReceiptPrice() == null ? tyre.getSellPrice()
					: tyre.getReceiptPrice();

			PdfPCell priceCell = new PdfPCell(new Phrase(price + "",
					PDF_SMALL_FONT_Orig));

			priceCell.setHorizontalAlignment(Element.ALIGN_RIGHT);
			table.addCell(priceCell);

			receiptPrice += tyre.getReceiptPrice();

		}

		for (Ring ring : sell.getRings()) {

			PdfPCell descriptionCell = new PdfPCell(new Phrase(ring.getName(),
					PDF_SMALL_FONT_Orig));
			descriptionCell.setHorizontalAlignment(Element.ALIGN_LEFT);
			table.addCell(descriptionCell);

			double price = ring.getReceiptPrice() == null ? ring.getSellPrice()
					: ring.getReceiptPrice();

			PdfPCell priceCell = new PdfPCell(new Phrase(price + "",
					PDF_SMALL_FONT_Orig));

			priceCell.setHorizontalAlignment(Element.ALIGN_RIGHT);
			table.addCell(priceCell);

			receiptPrice += ring.getReceiptPrice();

		}

		for (Battery battery : sell.getBatteries()) {

			PdfPCell descriptionCell = new PdfPCell(new Phrase(
					battery.getAmper(), PDF_SMALL_FONT_Orig));
			descriptionCell.setHorizontalAlignment(Element.ALIGN_LEFT);
			table.addCell(descriptionCell);

			double price = battery.getReceiptPrice() == null ? battery
					.getSellPrice() : battery.getReceiptPrice();

			PdfPCell priceCell = new PdfPCell(new Phrase(price + "",
					PDF_SMALL_FONT_Orig));
			priceCell.setHorizontalAlignment(Element.ALIGN_RIGHT);
			table.addCell(priceCell);

			receiptPrice += battery.getReceiptPrice();

		}

		for (LabourCharge labourCharge : sell.getLabourCharges()) {

			PdfPCell descriptionCell = new PdfPCell(new Phrase(
					labourCharge.getDescription(), PDF_SMALL_FONT_Orig));
			descriptionCell.setHorizontalAlignment(Element.ALIGN_LEFT);
			table.addCell(descriptionCell);

			double price = labourCharge.getReceiptPrice() == null ? labourCharge
					.getPrice() : labourCharge.getReceiptPrice();

			PdfPCell priceCell = new PdfPCell(new Phrase(price + "",
					PDF_SMALL_FONT_Orig));
			priceCell.setHorizontalAlignment(Element.ALIGN_RIGHT);
			table.addCell(priceCell);

			receiptPrice += labourCharge.getReceiptPrice();
		}

		PdfPCell totalCell = new PdfPCell(new Phrase("Total: " + receiptPrice,
				PDF_SMALL_FONT_BOLD_Orig));
		totalCell.setColspan(3);
		totalCell.setHorizontalAlignment(Element.ALIGN_RIGHT);
		totalCell.setBackgroundColor(TOTAL_COLOR);
		table.addCell(totalCell);

		document.add(table);

		PdfPTable footerTable = new PdfPTable(1);

		PdfPCell sellerCell = new PdfPCell(new Phrase("\n\nSeller: "
				+ sell.getSeller().getFirstName() + " " + sell.getSeller().getLastName(), PDF_SMALL_FONT_Orig));
		sellerCell.setBorder(0);

		footerTable.addCell(sellerCell);
		document.add(footerTable);

	}

	@RequestMapping(params = "showCart", method = RequestMethod.GET)
	public String showCart(Model uiModel, HttpServletRequest request) {
		uiModel.asMap().clear();
		Double actualPriceTotal = 0.0;
		Double receiptPriceTotal = 0.0;
		if (request.getSession().getAttribute("cart") != null) {
			Cart cart = (Cart) request.getSession().getAttribute("cart");
			List<Battery> batteries = new ArrayList<Battery>();
			for (Long id : cart.getBatteryIds()) {
				Battery battery = Battery.findBattery(id);
				batteries.add(battery);
				if (battery.getSellPrice() != null)
					actualPriceTotal += battery.getSellPrice();
				if (battery.getReceiptPrice() != null)
					receiptPriceTotal += battery.getReceiptPrice();
			}
			List<Ring> rings = new ArrayList<Ring>();
			for (Long id : cart.getRingIds()) {
				Ring ring = Ring.findRing(id);
				rings.add(ring);
				if (ring.getSellPrice() != null)
					actualPriceTotal += ring.getSellPrice();
				if (ring.getReceiptPrice() != null)
					receiptPriceTotal += ring.getReceiptPrice();
			}
			List<Tyre> tyres = new ArrayList<Tyre>();
			for (Long id : cart.getTyreIds()) {
				Tyre tyre = Tyre.findTyre(id);
				tyres.add(tyre);
				if (tyre.getSellPrice() != null)
					actualPriceTotal += tyre.getSellPrice();
				if (tyre.getReceiptPrice() != null)
					receiptPriceTotal += tyre.getReceiptPrice();
			}
			List<LabourCharge> labourCharges = new ArrayList<LabourCharge>();
			for (Long id : cart.getLabourChargeIds()) {
				LabourCharge tyre = LabourCharge.findLabourCharge(id);
				labourCharges.add(tyre);
				actualPriceTotal += tyre.getPrice();
				receiptPriceTotal += tyre.getReceiptPrice();
			}
			uiModel.addAttribute("batteries", batteries);
			uiModel.addAttribute("rings", rings);
			uiModel.addAttribute("tyres", tyres);
			uiModel.addAttribute("labourCharges", labourCharges);
			uiModel.addAttribute("actualPriceTotal", actualPriceTotal);
			uiModel.addAttribute("receiptPriceTotal", receiptPriceTotal);
		}
		uiModel.addAttribute("cart", request.getSession().getAttribute("cart"));
		return "sells/cart";
	}

	@RequestMapping(method = RequestMethod.POST)
	public String create(@Valid Sell sell, BindingResult bindingResult,
			Model uiModel, HttpServletRequest httpServletRequest) {
		if (bindingResult.hasErrors()) {
			uiModel.addAttribute("sell", sell);
			return "sells/create";
		}
		uiModel.asMap().clear();
		Operator seller = Operator.findOperator(Util.getCurrentUserName());
		sell.setSeller(seller);
		sell.persist();
		return "redirect:/sells/";
	}

	@RequestMapping(params = "form", method = RequestMethod.GET)
	public String editCartForm(Model uiModel, HttpServletRequest request) {
		uiModel.addAttribute("cart", request.getSession().getAttribute("cart"));
		return "sells/update";
	}

	@RequestMapping(method = RequestMethod.PUT)
	public String update(Sell sell, BindingResult bindingResult, Model uiModel,
			HttpServletRequest request, HttpServletResponse response) {
		Double actualPriceTotal = 0.0;
		Double receiptPriceTotal = 0.0;

		List<String> errors = new ArrayList<String>();
		if (sell.getName() == null || sell.getName().trim().equals(""))
			errors.add("Customer Name is empty");
		Cart cart = (Cart) request.getSession().getAttribute("cart");
		for (Long batteryId : cart.getBatteryIds()) {
			Battery battery = Battery.findBattery(batteryId);
			if (battery.getSellPrice() == null) {
				errors.add("Sell price is not set for Battery:" + battery);
			}
			sell.getBatteries().add(battery);
			actualPriceTotal += battery.getSellPrice() == null ? 0.0 : battery
					.getSellPrice();
			receiptPriceTotal += battery.getReceiptPrice() == null ? 0.0
					: battery.getReceiptPrice();
		}
		for (Long ringId : cart.getRingIds()) {
			Ring ring = Ring.findRing(ringId);
			if (ring.getSellPrice() == null) {
				errors.add("Sell price is not set for Ring:" + ring);
			}
			sell.getRings().add(ring);
			actualPriceTotal += ring.getSellPrice() == null ? 0.0 : ring
					.getSellPrice();
			receiptPriceTotal += ring.getReceiptPrice() == null ? 0 : ring
					.getReceiptPrice();
		}
		for (Long tyreId : cart.getTyreIds()) {
			Tyre tyre = Tyre.findTyre(tyreId);
			if (tyre.getSellPrice() == null) {
				errors.add("Sell price is not set for Tyre:" + tyre);
			}
			sell.getTyres().add(tyre);
			actualPriceTotal += tyre.getSellPrice() == null ? 0 : tyre
					.getSellPrice();
			receiptPriceTotal += tyre.getReceiptPrice() == null ? 0 : tyre
					.getReceiptPrice();
		}
		for (Long labourChargeId : cart.getLabourChargeIds()) {
			LabourCharge labourCharge = LabourCharge
					.findLabourCharge(labourChargeId);
			sell.getLabourCharges().add(labourCharge);
			actualPriceTotal += labourCharge.getPrice();
			receiptPriceTotal += labourCharge.getReceiptPrice();
		}
		if (errors.size() != 0) {
			uiModel.addAttribute("errors", errors);
			uiModel.addAttribute("name", sell.getName());
			uiModel.addAttribute("batteries", sell.getBatteries());
			uiModel.addAttribute("rings", sell.getRings());
			uiModel.addAttribute("tyres", sell.getTyres());
			uiModel.addAttribute("labourCharges", sell.getLabourCharges());
			uiModel.addAttribute("actualPriceTotal", actualPriceTotal);
			uiModel.addAttribute("receiptPriceTotal", receiptPriceTotal);

			return "sells/cart";
		}
		uiModel.asMap().clear();
		sell.setSellDate(new Date());
		for (Battery battery : sell.getBatteries())
			battery.setSellDate(new Date());
		for (Ring ring : sell.getRings())
			ring.setSellDate(new Date());
		for (Tyre tyre : sell.getTyres())
			tyre.setSellDate(new Date());
		for (LabourCharge labourCharge : sell.getLabourCharges())
			labourCharge.setSellDate(new Date());

		Operator seller = Operator.findOperator(Util.getCurrentUserName());
		sell.setSeller(seller);
		sell.persist();
		request.getSession().setAttribute("cart", null);
		return "redirect:/sells";
	}

	@PreAuthorize("hasAuthority('ROLE_ADMIN')")
	@RequestMapping(value = "/{id}", params = "form", method = RequestMethod.GET)
	public String updateForm(@PathVariable("id") Long id, Model uiModel) {
		uiModel.addAttribute("sell", Sell.findSell(id));
		addDateTimeFormatPatterns(uiModel);
		return "sells/update";
	}

	@PreAuthorize("hasAuthority('ROLE_ADMIN')")
	@RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
	public String delete(@PathVariable("id") Long id,
			@RequestParam(value = "page", required = false) Integer page,
			@RequestParam(value = "size", required = false) Integer size,
			Model uiModel) {
		Sell.findSell(id).remove();
		uiModel.asMap().clear();
		uiModel.addAttribute("page", (page == null) ? "1" : page.toString());
		uiModel.addAttribute("size", (size == null) ? "10" : size.toString());
		return "redirect:/sells";
	}

	@RequestMapping(params = "emptyCart", method = RequestMethod.GET)
	public String emptyCart(Model uiModel, HttpServletRequest request) {
		request.getSession().setAttribute("cart", null);
		return "redirect:/sells";
	}

}
